/*
//   Copyright 2008 Dear Soft(http://dear-soft.com)
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
 */

package com.dear.soft.components.path;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.SystemColor;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.prefs.Preferences;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.sun.imageio.plugins.common.ImageUtil;

public class PathPanel extends JPanel {
	private static final String HISTORY = "History";

	private static final String FAVORITES = "Favorites";

	private static final long serialVersionUID = 1L;

	private final static CellConstraints cc = new CellConstraints();
	private final String storeKey;
	private final String contextPath;

	private JToggleButton copyButton;
	private JToggleButton favoritesButton;
	private JToggleButton historyButton;
	private BreadCrumb breadcrumb;
	List<PathChangeListener> listeners = Collections
			.synchronizedList(new ArrayList<PathChangeListener>());

	public PathPanel(String contextPath, String storeKey) {
		this.contextPath = contextPath;
		this.storeKey = storeKey;
		initializeGui();
	}

	private void initializeGui() {
		setOpaque(true);
		setBackground(SystemColor.activeCaption);
		setForeground(SystemColor.activeCaptionText);
		breadcrumb = new BreadCrumb("/", SystemColor.activeCaptionText, 12,
				false);
		breadcrumb.setBackground(SystemColor.activeCaption);
		breadcrumb.setOpaque(true);
		breadcrumb.setRoot(contextPath);
		setLayout(new FormLayout("3px,50dlu:grow,2dlu,p,p,p", "p"));
		add(breadcrumb, cc.xy(2, 1, "f,f"));
		add(getCopyButton(), cc.xy(4, 1, "f,f"));
		add(getFavoritesButton(), cc.xy(5, 1, "f,f"));
		add(getHistoryButton(), cc.xy(6, 1, "f,f"));
	}

	private JComponent getHistoryButton() {
		if (historyButton != null) {
			return historyButton;
		}
		historyButton = new JToggleButton(
				new ImageIcon(
						ImageUtil.class
								.getResource("/com/dear/soft/components/path/res/gotohist.png")));
		setButtonSize(historyButton);
		historyButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (historyButton.isSelected()) {
					historyButton.setSelected(false);
					onShowHistory();
				}
			}
		});
		return historyButton;
	}

	protected void onShowHistory() {
		List<String> history = loadHistory();
		JPopupMenu menu = new JPopupMenu();

		int start = history.size() - 20;
		if (history.size() < 20) {
			start = Math.max(0, history.size() - 20);
		}
		for (int i = start; i < history.size(); i++) {
			JMenuItem item = new JMenuItem(history.get(i));
			item.addActionListener(new HistoryMenuItemActionListener(i));
			menu.add(item);
		}
		Point p = historyButton.getLocation();
		menu.show(this, p.x, p.y + 21);
	}

	protected void onFavorites() {
		List<String> favorites = loadFavorites();
		JPopupMenu menu = new JPopupMenu();
		for (int i = 0; i < favorites.size(); i++) {
			JMenuItem item = new JMenuItem(favorites.get(i));
			item.addActionListener(new FavoritesMenuItemActionListener(i));
			menu.add(item);
		}
		menu.addSeparator();
		JMenuItem add = new JMenuItem("Add current folder");
		add.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addCurrentFolderToFavorites();
			}
		});
		menu.add(add);
		JMenuItem configure = new JMenuItem("Configure...");
		configure.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				onConfigureFavorites();
			}
		});
		menu.add(configure);

		Point p = favoritesButton.getLocation();
		menu.show(this, p.x, p.y + 21);
	}

	protected void onConfigureFavorites() {
		List<String> items = loadFavorites();
		ConfigureDialog configureDialog = new ConfigureDialog(SwingUtilities
				.getWindowAncestor(this), items);
		configureDialog.setVisible(true);
		saveList(contextPath, storeKey, FAVORITES, configureDialog.getItems());

	}

	protected void addCurrentFolderToFavorites() {
		String path = breadcrumb.getPath();
		List<String> values = loadFavorites();
		if (values.indexOf(path) < 0) {
			values.add(path);
			saveList(contextPath, storeKey, FAVORITES, values);
		}
	}

	protected void addCurrentFolderToHistory() {
		List<String> values = loadHistory();
		values.add(breadcrumb.getPath());
		while (values.size() > 150) {
			values.remove(0);
		}
		saveList(contextPath, storeKey, HISTORY, values);
	}

	public void navigateFavoritesFolder(int index) {
		List<String> values = loadFavorites();
		if (values.size() > index) {
			String path = values.get(index);
			if (path.equals(this.breadcrumb.getPath())) {
				return;
			}
			breadcrumb.notifyListeners(path);
		}
	}

	public void navigateHistoryFolder(int index) {
		List<String> values = loadHistory();
		if (values.size() > index) {
			String path = values.get(index);
			if (path.equals(this.breadcrumb.getPath())) {
				return;
			}
			while (values.size() > (index + 1)) {
				values.remove(values.size() - 1);
			}
			saveList(contextPath, storeKey, HISTORY, values);
			breadcrumb.notifyListeners(path);
		}
	}

	public void navigateTo(String target) {
		if (target != null && !target.equals(breadcrumb.getPath())) {
			breadcrumb.setPath(target);
			addCurrentFolderToHistory();
		}
	}

	private List<String> loadHistory() {
		return loadList(contextPath, storeKey, HISTORY);
	}

	private List<String> loadFavorites() {
		return loadList(contextPath, storeKey, FAVORITES);
	}

	@SuppressWarnings("unchecked")
	private List<String> loadList(String docbase, String key, String section) {
		Preferences global = Preferences.userNodeForPackage(this.getClass());
		Preferences pref = global.node(docbase + "/" + key + "/" + section);
		byte[] bytes = pref.getByteArray("data", new byte[] {});
		if (bytes == null || bytes.length == 0) {
			return new ArrayList<String>();
		}
		try {
			ObjectInputStream in = new ObjectInputStream(
					new ByteArrayInputStream(bytes));
			return (List<String>) in.readObject();
		} catch (Throwable e) {
			// eh.. something wrong
		}
		return new ArrayList<String>();
	}

	private void saveList(String docbase, String key, String section,
			List<String> data) {
		Preferences global = Preferences.userNodeForPackage(this.getClass());
		Preferences pref = global.node(docbase + "/" + key + "/" + section);
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			ObjectOutputStream oout = new ObjectOutputStream(out);
			oout.writeObject(data);
			oout.flush();
			oout.close();
			pref.putByteArray("data", out.toByteArray());
			pref.sync();
		} catch (Throwable e) {
			// eh... nothing to do
		}
	}

	protected void onCopyToClipboard() {
		String path = breadcrumb.getPath();
		if (path != null && path.trim().length() > 1) {
			Clipboard clipboard = Toolkit.getDefaultToolkit()
					.getSystemClipboard();
			StringSelection stringSelection = new StringSelection(path);
			clipboard.setContents(stringSelection, new ClipboardOwner() {
				public void lostOwnership(Clipboard clipboard,
						Transferable contents) {
				}
			});
		}
	}

	private JComponent getFavoritesButton() {
		if (favoritesButton != null) {
			return favoritesButton;
		}
		favoritesButton = new JToggleButton(
				new ImageIcon(
						ImageUtil.class
								.getResource("/com/dear/soft/components/path/res/gotofolder.png")));
		setButtonSize(favoritesButton);

		favoritesButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (favoritesButton.isSelected()) {
					favoritesButton.setSelected(false);
					onFavorites();
				}
			}
		});
		return favoritesButton;
	}

	private JComponent getCopyButton() {
		if (copyButton != null) {
			return copyButton;
		}
		copyButton = new JToggleButton(
				new ImageIcon(
						ImageUtil.class
								.getResource("/com/dear/soft/components/path/res/copytoclipboard.png")));
		setButtonSize(copyButton);
		copyButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (copyButton.isSelected()) {
					copyButton.setSelected(false);
					onCopyToClipboard();
				}
			}
		});
		return copyButton;
	}

	private void setButtonSize(final JToggleButton btn) {
		btn.setSize(new Dimension(20, 20));
		btn.setPreferredSize(new Dimension(20, 20));
		btn.setMaximumSize(new Dimension(20, 20));
		btn.setBorder(BorderFactory.createEmptyBorder());
	}

	public void addPathChangeListener(PathChangeListener listener) {
		this.breadcrumb.addPathChangeListener(listener);
	}

	public void removePathChangeListener(PathChangeListener listener) {
		this.breadcrumb.removePathChangeListener(listener);
	}

	private class HistoryMenuItemActionListener implements ActionListener {
		private int index;

		public HistoryMenuItemActionListener(int index) {
			this.index = index;
		}

		public void actionPerformed(ActionEvent e) {
			navigateHistoryFolder(index);

		}
	}

	private class FavoritesMenuItemActionListener implements ActionListener {
		private int index;

		public FavoritesMenuItemActionListener(int index) {
			this.index = index;
		}

		public void actionPerformed(ActionEvent e) {
			navigateFavoritesFolder(index);

		}
	}

}
